<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Extjs_WebUploader</title>
    <!--引入CSS-->
    <link rel="stylesheet" type="text/css" href="js/ext/resources/theme-crisp/theme-crisp-all.css"/>
    <link rel="stylesheet" type="text/css" href="js/webuploader/webuploader.css">
    <link rel="stylesheet" type="text/css" href="css/icon.css">

    <!--引入JS-->
    <script type="text/javascript" src="js/ext/ext-all-debug.js"></script>
    <script type="text/javascript" src="js/ext/locale/ext-locale-zh_CN.js"></script>

    <script type="text/javascript" src="js/jquery/jquery.js"></script>
    <script type="text/javascript" src="js/webuploader/webuploader.js"></script>

</head>
<body>
    <script>


        Ext.Loader.setConfig({
            enabled: true
        });

        Ext.useShims = true;
        Ext.BLANK_IMAGE_URL = '';

        Ext.application({
            name: 'MyApp',
            launch: function() {
                var store = Ext.create('Ext.data.Store', {
                    autoLoad: false,
                    fields: ['id', 'fileName', 'fileType', 'fileSize', 'filePercent', 'status', 'code', 'picId']
                });

                var grid = Ext.create('Ext.grid.Panel', {
                    height: 400,
                    width: 750,
                    rowLines: true,
                    columnLines: true,
                    columns: [{
                        header: 'Id',
                        dataIndex: 'id',
                        hidden: true,
                        sortable: true,
                        menuDisabled: true
                    }, {
                        xtype: 'rownumberer',
                        width: 30
                    }, {
                        header: '文件名称',
                        flex: 1,
                        dataIndex: 'fileName',
                        sortable: true,
                        menuDisabled: true
                    },/** {
		        header: '文件类型',
		        width: 100,
		        dataIndex: 'fileType',
		        sortable: true,
		        menuDisabled: true
		    }, **/{
                        header: '文件大小',
                        width: 100,
                        dataIndex: 'fileSize',
                        sortable: true,
                        menuDisabled: true
                    }, {
                        header: '详细进度',
                        width: 100,
                        dataIndex: 'filePercent',
                        sortable: true,
                        menuDisabled: true
                    }, {
                        header: '状态',
                        width: 200,
                        dataIndex: 'status',
                        sortable: true,
                        menuDisabled: true
                    }, {
                        xtype: 'actioncolumn',
                        width: 20,
                        items: [{
                            icon: 'images/delete_record.png',
                            tooltip: '移除此记录',
                            handler: function(grid, rowIndex, colIndex, item , eOpts, record) {
                                var id = record.get('id');
                                grid.store.remove(record);
                                //未上传成功的移除掉
                                if('uploadSuccess' != record.get('code')){
                                    grid.up('grid').uploader.cancelFile(id);
                                }
                            }
                        }]
                    }],
                    store: store,
                    tbar: [{
                        xtype: 'label',
                        width: 83,
                        height: 24,
                        html: '<div style="line-height:24px;" id="webuploadPciker">' +
                            '<img style="position:relative;top:4px;left:-5px;" src="images/add.png" />' +
                            '选择文件</div>',
                    }, '-', {
                        iconCls: 'icon-picUpload',
                        text: '开始上传',
                        id: 'uploadButton',
                        handler: function(){
                            grid.uploader.upload();
                        }
                    }, '-', {
                        iconCls: 'icon-delete',
                        text: '清空列表',
                        handler: function(){
                            for(var i = 0; i < store.getCount();i++){
                                var record = store.getAt(i);
                                var file_id = record.get('id');
                                //未上传成功的移除掉
                                if('uploadSuccess' != record.get('code')){
                                    grid.uploader.cancelFile(file_id);
                                }
                            }
                            store.removeAll();
                        }
                    },'->',{ xtype:'label' , id:'speedLabel'}]
                });

                function measureBW(fn,time) {
                    time = time || 1;
                    var startTime, endTime, fileSize;
                    var count = time ;
                    var _this = this;
                    function measureBWSimple () {
                        var xhr = new XMLHttpRequest();

                        xhr.onreadystatechange = function() {
                            if (xhr.readyState === 4 && xhr.status === 200) {
                                if(!fileSize){
                                    fileSize = xhr.responseText.length;
                                }
                                count --;
                                if(count<=0){
                                    endTime = Date.now();
                                    var speed = fileSize * time  / ((endTime - startTime)/1000) / 1024;
                                    fn && fn(Math.floor(speed));
                                }
                            }
                        }
                        xhr.open("GET", "images/test.jpg?id=" + Math.random(), true);
                        xhr.send();
                    }
                    startTime = Date.now();
                    for(var x = time;x>0;x--){
                        measureBWSimple()
                    }
                }

                measureBW(function(speed){
                    Ext.getCmp('speedLabel').setText('您与服务器之间的网速大概为:'+parseInt(speed/1024)+"MB/SEC");
                },10)

                // function getSpeedWithAjax(url) {
                //     return new Promise((resolve, reject) => {
                //         let start = null;
                //         let end = null;
                //         start = new Date().getTime();
                //         const xhr = new XMLHttpRequest();
                //         xhr.onreadystatechange = function () {
                //             if (xhr.readyState === 4) {
                //                 end = new Date().getTime();
                //                 // byte --> kb --> mb
                //                 const size = xhr.getResponseHeader('Content-Length') / 1024 / 1024;
                //                 const speed = size * 1000 / (end - start)
                //                 console.log("speed:"+speed)
                //                 Ext.getCmp('speedLabel').setText('您的下载速度:'+parseInt(speed)+"M/S");
                //                 resolve(speed);
                //             }
                //         }
                //         xhr.open('GET', url);
                //         xhr.send();
                //     }).catch(err => { throw err });
                // }
                // getSpeedWithAjax("images/test.jpg?id="+Math.random());
                var md5 = {};
                var chunkUploadInfo = {};
                /**分片阈值*/
                var chunkedHoldSize = 50 * 1024 * 1024;
                /**分片大小*/
                var chunkedSize = 10 * 1024 * 1024;
                /**上传线程数**/
                var chunkedThreadNum = 3;

                grid.on('afterrender', function(){

                    // WebUploader提供的钩子（hook），在文件上传前先判断服务是否已存在这个文件
                    WebUploader.Uploader.register({
                        'before-send-file': 'beforeSendFile', //整个文件上传前
                        'before-send':'beforeSend'//分片上传前
                    }, {
                        beforeSendFile: function( file ) {
                            var that = this;
                            var deferred = $.Deferred();
                            /**上传前是否需要分片**/
                            if(file.size > chunkedHoldSize){
                                /**是否使用分片*/
                                uploader.options.chunked = true;
                                /**分片大小*/
                                uploader.options.chunkSize = chunkedSize;
                                /**分片重试*/
                                uploader.options.chunkRetry = false;
                                /**上传线程数*/
                                uploader.options.threads = chunkedThreadNum;
                                /**上传连接**/
                                uploader.options.server = 'file/uploadChunk';
                            }else{
                                /**上传线程数*/
                                uploader.options.threads = 3;
                                uploader.options.chunked = false;
                                uploader.options.server = 'file/upload';
                            }

                            /**判断秒传(md5校验),是否续传**/
                            //上传前请求服务端,判断文件是否已经上传过
                            $.post("file/getUploadPreInfo",
                                {
                                    md5:md5[file.id],
                                    type:file.source.type,
                                    lastModifiedDate: file.source.lastModifiedDate,
                                    fileSize: file.source.size,
                                    name: file.source.name,
                                    chunkSize: chunkedSize
                                },
                                function(data)
                                {
                                    console.log(data);
                                    if(data.status == '100'){ /**秒传**/
                                    that.owner.skipFile(file);
                                        deferred.resolve();
                                    }else if(data.status == '101'){/**续传**/
                                    chunkUploadInfo = data.chunkInfo;
                                        deferred.resolve();
                                    }else{
                                        deferred.resolve();
                                    }
                                });
                            return deferred.promise();
                        },
                        beforeSend: function(block){
                            console.log(block);
                            var deferred = WebUploader.Deferred();
                            if(chunkUploadInfo!= null && contains(chunkUploadInfo,block.chunk+'')){
                                deferred.reject();
                            }else{
                                deferred.resolve();
                            }
                            this.owner.options.formData.md5 = md5[block.file.id];
                            this.owner.options.formData.chunkSize = chunkedSize;
                            this.owner.options.formData.fileSize = block.file.source.size;
                            this.owner.options.formData.ext = block.file.source.ext;
                            return deferred.promise();
                        }
                    });

                    /**加载部分内容*/
                    var uploader = grid.uploader = WebUploader.create({
                        //swf文件路径
                        swf: 'js/webuploader/Uploader.swf',
                        //文件接收服务端。
                        server: 'pic/save',
                        //选择文件的按钮。可选。 内部根据当前运行是创建，可能是input元素，也可能是flash.
                        pick: '#webuploadPciker',
                        //不压缩image, 默认如果是jpeg，文件上传前会压缩一把再上传！
                        resize: false,
                        fileNumLimit: 20
                    });

                    // 当有文件被添加进队列的时候
                    uploader.on('fileQueued', function(file) {
                        Ext.getCmp('uploadButton').disable();
                        store.add({
                            id : file.id,
                            fileName : file.name,
                            fileSize : Math.round(file.size*100/(1024*1024))/100+"M",
                            fileType : file.type,
                            status : '待上传',
                            filePercent : '0',
                            code: 'fileQueued',
                            md5: ''
                        });
                        let record = store.getById(file.id);
                        //获取文件MD5值
                        md5[file.id] = '';
                        uploader.md5File( file )// 及时显示进度
                            .progress(function(percentage) {
                                record.set('filePercent', parseInt(percentage * 100) + '%');
                                record.set('status', '读取文件,计算MD5');
                            })
                            // 完成
                            .then(function(val) {
                                record.set('status','等待上传');
                                md5[file.id] = val;
                                record.set('md5',val);
                                var flag = false;
                                store.each(function(record){
                                    console.log(record);
                                    if(record.get('status')!='等待上传'){
                                        flag = true;
                                    }
                                })
                                if(!flag){
                                    Ext.getCmp('uploadButton').enable();
                                }
                            });
                    });

                    uploader.on('error', function (code, file) {
//            	var name = file.name;
                        var str = '上传出错!请检查后重新上传!错误代码:' + code;
                        switch(code){
                            case 'F_DUPLICATE':
                                str = '文件重复上传!';
                                break;
                            case 'Q_TYPE_DENIED':
                                str = '文件类型不允许!';
                                break;
                            case 'F_EXCEED_SIZE':
                                str = '文件大小超出限制,文件大小不能超过2M!';
                                break;
                            case 'Q_EXCEED_SIZE_LIMIT':
                                str = '超出空间文件大小!';
                                break;
                            case 'Q_EXCEED_NUM_LIMIT':
                                str = '超过上传数量图片限制!';
                                break;
                        }
                        Ext.Msg.alert('系统提示', str);
                    });

                    // 文件上传过程中创建进度条实时显示。
                    uploader.on('uploadProgress', function(file, percentage ) {
                        var record = store.getById(file.id);
                        record.set('filePercent', parseInt(percentage * 100) + '%');
                        record.set('status', '上传中');
                        record.set('code', 'uploadProgress');
                        record.commit();
                    });

                    uploader.on('uploadSuccess', function(file, response) {
                        var deferred = $.Deferred();
                        var record = store.getById(file.id);
                        /**附件上传成功后，调用合并的接口*/
                        $.post("file/mergeChunk", {
                            md5 : record.get('md5'),
                            fileSize: file.source.size,
                            name: file.source.name,
                            chunkSize: chunkedSize
                        },function(result){
                            if(result.code == '200'){
                                record.set('status', '上传成功');
                                record.set('code', 'uploadSuccess');
                                record.commit();
                            }
                        });
                        deferred.resolve();
                    });

                    uploader.on('uploadError', function(file) {
                        var record = store.getById(file.id);
                        record.set('filePercent', '0');
                        record.set('status', '上传失败,网络异常!');
                        record.set('code', 'uploadError');
                        record.commit();
                    });

                    uploader.on('uploadComplete', function(file) {
                        var record = store.getById(file.id);
                        if('uploadSuccess' == record.get('code')){

                        }
                    });
                });
                grid.render(Ext.getBody());


            }

        });





        function contains(arr, obj) {
            var i = arr.length;
            while (i--) {
                if (arr[i] === obj) {
                    return true;
                }
            }
            return false;
        }
    </script>
</body>
</html>